分布式系列 (二) 一致性协议 2PC和3PC

喵了个喵,我又遇到瓶颈了

[TOC]

为解决分布式问题,涌现了一大批经典的一致性协议和算法。最著名的就是2PC,3PC,和Paxos算法。

2PC和3PC

当一个事务操作需要跨越多个分布式节点的时候,为保持事务处理的ACID特性,需要引入一个协调者来统一调度所有分布式节点的执行逻辑,这些被调度的分布式节点被称为参与者。协调者负责调度参与者的行为,并最终决定这些参与者是否要把事务真正提交。由此衍生出2pc和3pc

2PC 二阶段提交协议

二阶段提交协议是把事务的提交过程分成两个阶段处理。

  • 阶段一:提交事务请求
  • 阶段二:执行事务提交

二阶段提交的核心思想就是对每一个事务都采用先尝试后提交的处理方式,因此也可以将二阶段提交看作是一个强一致性算法。

阶段1中,协调者发起一个提议,分别问询各参与者是否接受

![image-20190922233819996](分布式系列-二-一致性协议 2PC和3PC/image-20190922233819996.png)

在阶段2中,协调者根据参与者的反馈,提交或中止事务,如果参与者全部同意则提交,只要有一个参与者不同意就中止。

![image-20190922233839319](分布式系列-二-一致性协议 2PC和3PC/image-20190922233839319.png)

二阶段提交有几个优点:原理简单,容易实现。

二阶段提交有几个缺点:

  • 同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
  • 单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
  • 数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
  • 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

3PC 三阶段提交协议

三阶段提交(3PC),是二阶段提交(2PC)的改进。有两个改动点。

  • 引入超时机制。同时在协调者和参与者中都引入超时机制。
  • 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

三阶段提交有以下3个阶段:

  • 阶段一:CanCommit。

    事务询问,参与者响应。协调者询问是否可以进行事务操作,参与者反馈

  • 阶段二:PreCommit。

    两种可能。

    1.协调者获得的所有反馈都是Yes,执行事务的预执行。

    • 发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
    • 事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
    • 响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

    2.任一个参与者向协调者发送了No,或等待超时。执行事务的中断。

    • 发送中断请求 协调者向所有参与者发送abort请求。
    • 中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
  • 阶段三:doCommit

    该阶段进行真正的事务提交,也分两种情况。

    1.执行提交

    • 发送提交请求 协调者收到所有Ack响应,将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
    • 事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
    • 响应反馈 事务提交完之后,向协调者发送Ack响应。
    • 完成事务 协调者接收到所有参与者的Ack响应之后,完成事务。

    2.中断事务

    协调者没有完全接收到所有的Ack响应,执行中断事务。

    • 协调者向所有参与者发送abort中断请求
    • 事务回滚。参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
    • 反馈结果。参与者完成事务回滚之后,向协调者发送Ack消息
    • 中断事务。协调者接收到参与者反馈的Ack消息之后,执行事务的中断。

![image-20190923233335948](分布式系列-二-一致性协议 2PC和3PC/image-20190923233335948.png)

2PC和3PC的区别

相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,参与者会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。

在2PC中一个参与者的状态只有它自己和协调者知晓,假如协调者提议后自身宕机,在协调者备份启用前一个参与者又宕机,其他参与者就会进入既不能回滚、又不能强制commit的阻塞状态,直到参与者宕机恢复。

参与者如果在不同阶段宕机,3PC如何应对:

  • 阶段1: 协调者或协调者备份未收到宕机参与者的vote,直接中止事务;宕机的参与者恢复后,读取logging发现未发出赞成vote,自行中止该次事务
  • 阶段2: 协调者未收到宕机参与者的precommit ACK,但因为之前已经收到了宕机参与者的赞成反馈(不然也不会进入到阶段2),协调者进行commit;协调者备份可以通过问询其他参与者获得这些信息,过程同理;宕机的参与者恢复后发现收到precommit或已经发出赞成vote,则自行commit该次事务
  • 阶段3: 即便协调者或协调者备份未收到宕机参与者t的commit ACK,也结束该次事务;宕机的参与者恢复后发现收到commit或者precommit,也将自行commit该次事务
文章目录
  1. 1. 2PC和3PC
    1. 1.1. 2PC 二阶段提交协议
    2. 1.2. 3PC 三阶段提交协议
  2. 2. 2PC和3PC的区别
|